package com.example.lottery.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.example.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.example.lottery.common.exception.ServiceException;
import com.example.lottery.common.utils.JWTUtil;
import com.example.lottery.common.utils.RegexUtil;
import com.example.lottery.controller.param.ShortMessageLoginParam;
import com.example.lottery.controller.param.UserLoginParam;
import com.example.lottery.controller.param.UserPasswordLoginParam;
import com.example.lottery.controller.param.UserRegisterParam;
import com.example.lottery.dao.datobject.Encrypt;
import com.example.lottery.dao.datobject.UserDO;
import com.example.lottery.dao.mapper.UserMapper;
import com.example.lottery.service.UserService;
import com.example.lottery.service.VerificationCodeService;
import com.example.lottery.service.dto.UserDTO;
import com.example.lottery.service.dto.UserLoginDTO;
import com.example.lottery.service.dto.UserRegisterDTO;
import com.example.lottery.service.enums.UserIdentityEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private VerificationCodeService verificationCodeService;
    @Override
    public UserRegisterDTO register(UserRegisterParam request) {
        //检验参数
        checkRegisterInfo(request);
        UserDO userDO=new UserDO();
        userDO.setUserName(request.getName());
        userDO.setEmail(request.getMail());
        userDO.setPhoneNumber(new Encrypt(request.getPhoneNumber()));
        userDO.setIdentity(request.getIdentity());
        if(StringUtils.hasText(request.getPassword())){
            //对密码进行加密，不可逆的
            userDO.setPassword(DigestUtil.sha256Hex(request.getPassword()));
        }
        userMapper.insert(userDO);

        UserRegisterDTO userRegisterDTO=new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());
        return userRegisterDTO;
    }

    private void checkRegisterInfo(UserRegisterParam request) {
        if(request==null){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        if(!RegexUtil.checkMail(request.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        if(!RegexUtil.checkMobile(request.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        if(UserIdentityEnum.forName(request.getIdentity())==null){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //管理员必须设置密码
        if(request.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())&&!
                StringUtils.hasText(request.getPassword())){
            //相当于是管理员，但是管理员没设密码
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }

        //密码格式检验，最少6位，最多12位
        if(StringUtils.hasText(request.getPassword())&&!RegexUtil.checkPassword(request.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //检验邮箱是否被使用
        if(checkMailUsed(request.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }
        //检验手机号是否被使用
        if(checkPhoneNumberUsed(request.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }
    }

    private boolean checkPhoneNumberUsed(String phoneNumber) {
        int count=userMapper.countByPhone(new Encrypt(phoneNumber));
        return count>0;

    }

    private boolean checkMailUsed(String mail) {
        int count=userMapper.countByMail(mail);
        return count>0;
    }

    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO=null;

        //类型检查与类型转换
        if(param instanceof UserPasswordLoginParam loginParam){
            //走密码登陆流程
            userLoginDTO=loginByUserPassword(loginParam);
        }else if(param instanceof ShortMessageLoginParam loginParam){
            //走短信验证码登陆
            userLoginDTO=loginByShortMessage(loginParam);
        }else{
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }
        return userLoginDTO;

    }

    /**
     * 验证码登陆
     * @param loginParam
     * @return
     */

    private UserLoginDTO loginByShortMessage(ShortMessageLoginParam loginParam) {
        if(!RegexUtil.checkMobile(loginParam.getLoginMobile())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }
        //获取用户数据
       UserDO userDO=userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginMobile()));
        if(userDO==null){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        }else if(StringUtils.hasText(loginParam.getMandatoryIdentity())
        &&!loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //检验验证码
        String code = verificationCodeService.getVerificationCode(loginParam.getLoginMobile());
        if(!loginParam.getVerificationCode().equals(code)){
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
        //塞入返回值
        Map<String,Object> claim=new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        String token= JWTUtil.genJwt(claim);
        UserLoginDTO userLoginDTO=new UserLoginDTO();
        userLoginDTO.setToken(token);
        //UserLoginDTO 里面的Identity的返回对象 是枚举类
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    /**
     * 密码登陆
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {
        UserDO userDO=null;
        //判断是手机登录还是邮箱登陆
        if(RegexUtil.checkMail(loginParam.getLoginName())){
            //邮箱登录
            //根据邮箱查询用户表
            userDO=userMapper.selectByMail(loginParam.getLoginName());
        }else if(RegexUtil.checkMobile(loginParam.getLoginName())){
            //手机号登陆
            //根据手机号查询用户表
            userDO=userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));
        }else{
            //登陆方式不存在
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }
        if(userDO==null){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        }else if(StringUtils.hasText(loginParam.getMandatoryIdentity())
        &&!loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }else if(!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //塞入返回值
        Map<String,Object> claim=new HashMap<>();
        claim.put("id",userDO.getId());
        claim.put("identity",userDO.getIdentity());
        String token= JWTUtil.genJwt(claim);
        UserLoginDTO userLoginDTO=new UserLoginDTO();
        userLoginDTO.setToken(token);
        //UserLoginDTO 里面的Identity的返回对象 是枚举类
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identity) {
        //identity.name 相当于就是一个字符串 “ADMIN" or "NORMAL"
        String identityString=null==identity ?null:identity.name();

        //查表
        List<UserDO> userDOList=userMapper.selectUserListByIdentity(identityString);
        List<UserDTO> userDTOList=userDOList.stream()
                .map(userDO -> {
                    //这里吧UserDO的所有的属性都映射给了UserDTO
                    UserDTO userDTO=new UserDTO();
                    userDTO.setUserId(userDO.getId());
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setEamil(userDO.getEmail());
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
                    return userDTO;
                }).collect(Collectors.toList());
        return userDTOList;
    }
}
